import {
  Component,
  HostBinding,
  Input,
  Output,
  EventEmitter,
  QueryList,
  AfterViewInit,
  ViewChildren,
  ViewContainerRef,
  OnChanges,
  SimpleChanges,
  ChangeDetectorRef,
  ElementRef,
  OnInit,
  ChangeDetectionStrategy,
  ContentChildren,
  OnDestroy,
} from '@angular/core';

import { TabPaneDirective } from './tab-pane.directive';
import { merge, Subscription } from 'rxjs';

export type TabType = 'line' | 'card';

@Component({
  selector: 'fui-tab',
  templateUrl: './tab.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class TabComponent implements AfterViewInit, OnInit, OnChanges, OnDestroy {
  @HostBinding('class.fui-tab') true;

  @ViewChildren('wrapper', {read: ViewContainerRef}) wrappers: QueryList<ViewContainerRef>;

  @ViewChildren('item') tabItems: QueryList<ElementRef<HTMLElement>>;

  @ContentChildren(TabPaneDirective) panes: QueryList<TabPaneDirective>;

  /** Currently selected tab's index. */
  // TODO(0.7.0): selectedIndex -> selectedKey
  @Input() selectedIndex: any;

  /** Tab style type, support 'line', 'card'. */
  @Input() type: TabType = 'line';

  /** Emit selected tab's index. */
  @Output() selectedIndexChange = new EventEmitter();

  linkBarStyle = {left: 0, width: 0};

  get activePane() {
    return this.panes.find((p) => p.active);
  }

  get paneArr() {
    return this.panes.toArray();
  }

  titleSub: Subscription;

  constructor(private cdf: ChangeDetectorRef) {}

  ngOnInit() {
  }

  ngAfterViewInit() {
    this.panes.changes.subscribe(() => {
      this.registerTitleChange();
      this.cdf.detectChanges();
    });

    this.registerTitleChange();

    this.initPanes();
    // 这边使用this.wrappers.changes会使得在activate时报错，因为tabItems还未changes完毕
    this.tabItems.changes
    .subscribe(() => {
      this.initPanes();
      this.cdf.detectChanges();
    });
  }

  ngOnChanges(changes: SimpleChanges) {
    const {selectedIndex: selectedIndexChange} = changes;
    if (selectedIndexChange && selectedIndexChange.currentValue !== undefined) {
      setTimeout(() => {
        const pane = this.panes.find((p) => p.key === this.selectedIndex);
        this.activate(pane);
      });
    }
  }

  initPanes() {
    const wrappers = this.wrappers.toArray();
    this.panes.forEach((p, i) => {
      const wrapper = wrappers[i];
      p.init(wrapper, i, false);
    });
    const activePane = this.panes.find((p) => p.active);
    if (!activePane) {
      if (this.paneArr.length > 0) {
        const defaultPane = this.paneArr[0];
        this.activate(defaultPane);
      }
    } else {
      this.activate(activePane);
    }
  }

  selectPane(pane: TabPaneDirective) {
    if (!pane) {
      return;
    }

    this.activate(pane);

    this.selectedIndexChange.emit(pane.key);
  }

  activate(pane: TabPaneDirective) {
    const slideDirection = this.calcSlideDirection(pane, this.activePane);
    this.panes.forEach((p) => p.active = false);
    pane.active = true;

    this.renderBar(pane);

    this.panes.forEach((p) => {
      if (p === pane) {
        p.show(slideDirection);
      } else {
        p.hide(slideDirection);
      }
    });

    this.cdf.detectChanges();
  }

  calcSlideDirection(toPane: TabPaneDirective, fromPane: TabPaneDirective) {
    let slideDirection;
    if (fromPane) {
      const fromIdx = this.paneArr.findIndex((p) => p === fromPane);
      const toIdx = this.paneArr.findIndex((p) => p === toPane);
      slideDirection = toIdx > fromIdx ? 'left' : 'right';
    }
    return slideDirection;
  }

  renderBar(pane: TabPaneDirective) {
    const idx = this.paneArr.findIndex((p) => p === pane);

    // 直接取item当前的offsetLeft在某些情况下不准确，应该是dom还未更新
    const itemArr = this.tabItems.toArray();
    let left = itemArr[0].nativeElement.offsetLeft;
    itemArr.slice(0, idx).forEach((i) => {
      // 2 为自然margin
      left += i.nativeElement.offsetWidth + 2;
    });
    const item = this.tabItems.toArray()[idx].nativeElement;
    const {offsetWidth: width} = item;
    Object.assign(this.linkBarStyle, {left, width});
  }

  registerTitleChange() {
    if (this.titleSub) {
      this.titleSub.unsubscribe();
    }

    this.titleSub = merge(
      ...this.panes.map((p, i) => p.titleChangeSubj),
    )
    .subscribe(() => {
      this.cdf.detectChanges();
    });
  }

  ngOnDestroy() {
    if (this.titleSub) {
      this.titleSub.unsubscribe();
    }
  }
}
